/**
 * @Title: SheetPrintController.java
 * @Package: OThinker.H3.Controller.Controllers.ProcessModel
 * @Description: SheetPrintController
 * @Author: linjh
 * @Date: 2017年7月19日 下午7:37:49
 * @Version: V1.0
 */
package OThinker.H3.Controller.Controllers.ProcessModel;

import OThinker.Common.Data.BoolMatchValue;
import OThinker.Common.DateTimeUtil;
import OThinker.Common.DotNetToJavaStringHelper;
import OThinker.Common.Organization.Models.Unit;
import OThinker.H3.Controller.MvcSheet.MvcPage;
import OThinker.H3.Controller.MvcSheet.MvcViewContext;
import com.h3bpm.base.util.AppUtility;
import OThinker.H3.Entity.Data.Attachment.AttachmentHeader;
import OThinker.H3.Entity.Data.Comment;
import OThinker.H3.Entity.Data.DataLogicType;
import OThinker.H3.Entity.DataModel.BizObject;
import OThinker.H3.Entity.DataModel.PropertySchema;
import OThinker.H3.Entity.IEngine;
import OThinker.H3.Entity.Instance.Data.IInstanceDataItem;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ClassName: SheetPrintController
 * @Description: 表单打印
 * @Author: linjh
 * @Date: 2017年7月19日 下午7:37:49
 */
public class SheetPrintController extends MvcPage {

    private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(SheetPrintController.class);

    /**
	 * @Fields serialVersionUID : 
	 */
	private static final long serialVersionUID = 2984925702290151505L;
	
	/**
	 * @Title: SheetPrintController
	 * @Description: 构造函数
	 * @Param: 
	 * @throws
	 */
	public SheetPrintController() {
		
	}
	
	/**
	 * @Title: SheetPrintController
	 * @Description: 构造函数
	 * @Param: 
	 * @throws
	 */
	public SheetPrintController(HttpServletRequest request, HttpServletResponse response) {
		super(request, response);
	}
	
	/**
	 * 默认表单属性
	 */
    /**
     * 获取资源文件访问对象
     */
    //protected System.Resources.ResourceManager PortalResource
    //{
    //    get
    //    {
    //        return Resources.Resource.ResourceManager;
    //    }
    //}

    /**
     * 流程引擎的接口，该接口会比this.Engine的方式更快，因为其中使用了缓存
     * @throws Exception 
     */
    public IEngine getEngine() throws Exception {
		return AppUtility.getEngine();
    }

    /**
     * updated by linwp
     * <p>Title: LoadDataFields</p>
     * <p>Description: 表单加载事件</p>
     * @return
     * @throws Exception 
     * @see MvcPage#LoadDataFields()
     */
    @Override
    public MvcViewContext LoadDataFields(String lan_type) throws Exception{
       MvcViewContext viewContext =  super.LoadDataFields(lan_type);
       return viewContext;
    }

    public String GetPrintContent() throws Exception {
        String printModel = this.getActionContext().getSheet().getPrintModel();
        if (DotNetToJavaStringHelper.isNullOrEmpty(printModel)){
        	return null;
        }
        String printContent = GetPrintContentString(printModel);
        
        Map<String, String> temp = new HashMap<String, String>();
        temp.put("printContent", printContent);
        ObjectMapper result = new ObjectMapper();
        return result.writeValueAsString(temp);
    }

    /**
     * @Title: GetPrintContentString
     * @Description: 获取打印内容
     * @Param: @param printModel
     * @Param: @return
     * @Return: String
     * @throws Exception
     */
    public String GetPrintContentString(String printModel) throws Exception{
        StringBuilder printContent = new StringBuilder();
        // 优先处理子表
        String[] grids = printModel.split("<Row>");
        if (grids.length > 1){
        	String rowTemplate = "";
            for (int i = 0; i < grids.length; i++){
                if (i == 0 || grids[i].indexOf("}") == -1){
                    printContent.append(grids[i]);
                    continue;
                }
                rowTemplate = grids[i].substring(0, grids[i].indexOf("</Row>"));
                printContent.append(GetGridValue(rowTemplate));
                printContent.append(grids[i].substring(grids[i].indexOf("</Row>") + 6));
            }
        } else {
            printContent.append(printModel);
        }
        //处理审批意见多条的情况
        GetComments(printContent);

        // 处理数据项
        String[] fields = printContent.toString().split("\\{");
        if (fields.length == 1){
        	return printContent.toString();
        }
        printContent = new StringBuilder();
        String field;
        for (int i = 0; i < fields.length; i++){
            if (i == 0 || fields[i].indexOf("}") == -1){
                printContent.append(fields[i]);
                continue;
            }
            field = fields[i].substring(0, fields[i].indexOf("}"));
            printContent.append(GetFieldValue(field));
            printContent.append(fields[i].substring(fields[i].indexOf("}") + 1));
        }
        return printContent.toString();
    }

   // 处理审批意见多条的情况
    private void GetComments(StringBuilder printContent) throws Exception {
        String printModel;
        printModel = printContent.toString();
        printContent.setLength(0);
        String[] comments = printModel.split("<Comment>");
        if (comments.length > 1){
            String rowTemplate = "";
            for (int i = 0; i < comments.length; i++){
                if (i == 0 || comments[i].indexOf("}") == -1){
                    printContent.append(comments[i]);
                    continue;
                }
                rowTemplate = comments[i].substring(0, comments[i].indexOf("</Comment>"));
                printContent.append(GetCommentValue(rowTemplate));
                printContent.append(comments[i].substring(comments[i].indexOf("</Comment>") + 10));
            }
        } else {
            printContent.append(printModel);
        }
    }

    /**
     *  处理审批意见 内容
     * @param rowTemplate
     * @return
     * @throws Exception
     */
    private String GetCommentValue(String rowTemplate) throws Exception{
        String[] fields = rowTemplate.toString().split("\\{");
        if (fields.length == 1){
            return rowTemplate;
        }

        String bizObjectField = "";  // 业务对象数组编码

        for (int i = 1; i < fields.length; i++){
            bizObjectField = fields[i].substring(0, fields[i].indexOf("}"));
            if (bizObjectField.indexOf(".") > 0) bizObjectField = bizObjectField.substring(0, bizObjectField.indexOf("."));
            if (this.getActionContext().getInstanceData().getItem(bizObjectField) != null
                    && this.getActionContext().getInstanceData().getItem(bizObjectField).getLogicType() == DataLogicType.Comment){
                break;
            }
            bizObjectField = "";
        }

        // 没有找到业务对象数组数据项
        if ("".equals(bizObjectField)){
            return rowTemplate;
        }

        Comment[] comments = GetComments(bizObjectField, "", "");

        if (comments == null ){
            return "";
        }

        StringBuilder commentsContext = new StringBuilder();
        String field;
        for(Comment obj : comments){
            for (int i = 0; i < fields.length; i++){
                if (i == 0 || fields[i].indexOf("}") == -1){
                    commentsContext.append(fields[i]);
                    continue;
                }
                field = fields[i].substring(0, fields[i].indexOf("}"));
                if (field.indexOf(".") > 0) field = field.substring(field.indexOf(".") + 1);

                String result = "";

                if ("username".equals(field.toLowerCase())){
                    Unit u = this.getEngine().getOrganization().GetUnit(obj.getUserID());
                    result = u != null ? u.getName() : obj.getUserID();
                } else if ("datetime".equals(field.toLowerCase())) {
                    SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");
                    result = sdf2.format(obj.getCreatedTime());
                } else {
                    result = obj.getText();
                }
                commentsContext.append(result);
                commentsContext.append(fields[i].substring(fields[i].indexOf("}") + 1));
            }
        }

        return  commentsContext.toString();
    }

    /**
     * @Title: GetGridValue
     * @Description: 获取子表内容
     * @Param: @param rowTemplate
     * @Param: @return
     * @Return: String
     * @throws Exception
     */
    private String GetGridValue(String rowTemplate) throws Exception{
        // 获取第一个业务对象数组数据项
    	String[] fields = rowTemplate.toString().split("\\{");
        if (fields.length == 1){
        	return rowTemplate;
        }
        String bizObjectField = "";  // 业务对象数组编码

        for (int i = 1; i < fields.length; i++){
            bizObjectField = fields[i].substring(0, fields[i].indexOf("}"));
            if (bizObjectField.indexOf(".") > 0) bizObjectField = bizObjectField.substring(0, bizObjectField.indexOf("."));
            if (this.getActionContext().getInstanceData().getItem(bizObjectField) != null
                && this.getActionContext().getInstanceData().getItem(bizObjectField).getLogicType() == DataLogicType.BizObjectArray){
                break;
            }
            bizObjectField = "";
        }

        // 没有找到业务对象数组数据项
        if ("".equals(bizObjectField)){
        	return rowTemplate;
        }

        BizObject[] bizObjects = (BizObject[]) this.getActionContext().getInstanceData().getItem(bizObjectField).getValue();
        if (bizObjects == null || bizObjects.length == 0){
        	return "";
        }

        StringBuilder gridContent = new StringBuilder();
        String field;
        for(BizObject obj : bizObjects){
            for (int i = 0; i < fields.length; i++){
                if (i == 0 || fields[i].indexOf("}") == -1){
                    gridContent.append(fields[i]);
                    continue;
                }

                field = fields[i].substring(0, fields[i].indexOf("}"));
                if (field.indexOf(".") > 0) field = field.substring(field.indexOf(".") + 1);

                gridContent.append(GetBizObjectFieldValue(obj, field));
                gridContent.append(fields[i].substring(fields[i].indexOf("}") + 1));
            }
        }
        return gridContent.toString();
    }

    /**
     * @Title: GetBizObjectFieldValue
     * @Description: 获取业务对象的字段值
     * @Param: @param obj
     * @Param: @param field
     * @Param: @return
     * @Return: String
     * @throws Exception
     */
    @SuppressWarnings("deprecation")
	private String GetBizObjectFieldValue(BizObject obj, String field) throws Exception{
        PropertySchema property = obj.getSchema().GetProperty(field);
        if (property == null){
        	return "";
        }
        String result = "";

        switch (property.getLogicType()){
            case String:
            case ShortString:
            case Decimal:
            case Double:
            case Int:
            case Html:
            case Long:
            case TimeSpan:
                result = obj.getItem(field) + "";
                break;
            case DateTime:
                //Date d = new Date();
                Object dateItem = obj.getItem(field);
                String format = dateItem == null ? "" : DateTimeUtil.format((Date) dateItem, "yyyy-MM-dd HH:mm:ss");
                LOGGER.info("子表打印数据 格式化时间：{}, 原时间：{}",format,dateItem);
                //Update by linjh
    			return format;
            case SingleParticipant:
                if (!"".equals(obj.getItem(field) + "")){
                    result = this.getEngine().getOrganization().GetName(obj.getItem(field) + "");
                }
                break;
            case MultiParticipant:
                {
                    String[] users = (String[]) obj.getItem(field);
                    if (users != null && users.length > 0){
                    	List<String> temp = Arrays.asList(users);
                    	List<Unit> temp2 = this.getEngine().getOrganization().GetUnits(temp);
                    	//Update by linjh
                    	//增加对temp2的判断
                    	Unit[] units = null;
                        if(temp2 != null && temp2.size() > 0){
                        	units = temp2.toArray(new Unit[temp2.size()]);
                        }
                        if (units != null){
                            for(Unit unit : units){
                                result += "".equals(result) ? "" : "、";
                                result += unit.getName();
                            }
                        }
                    }
                }
                break;
            case Attachment:
                {
                	List<AttachmentHeader> temp = this.getEngine().getBizObjectManager().QueryAttachment(
                            this.getActionContext().getSchemaCode(),
                            obj.getObjectID(),
                            field,
                            BoolMatchValue.True,
                            null);
                	//Update by linjh
                	//增加对temp的判断
                	AttachmentHeader[] headers = null;
                    if(temp != null && temp.size() > 0){
                    	headers = temp.toArray(new AttachmentHeader[temp.size()]);
                    }
                    if (headers != null){
                        for (int i = 0; i < headers.length; i++){
                            result += "".equals(result) ? "" : "<br>";
                            result += (i + 1) + "、" + headers[i].getFileName();
                        }
                    }
                }
                break;
            case Bool:
                boolean b = false;
                b = Boolean.parseBoolean(obj.getItem(field) + "");
                result = b ?"true" : "false";
                break;
            default:
                result = "";
                break;
        }
        return result;
    }

    /**
     * @Title: GetFieldValue
     * @Description: 获取指定数据项的值
     * @Param: @param field
     * @Param: @return
     * @Return: String
     * @throws Exception
     */
	private String GetFieldValue(String field) throws Exception{
    	String param = "";
        String dateFilter =null;
    	if (field != null){
            String[] fieldAry = field.split(";");
            String filter ="";
            if (fieldAry.length>1){
                filter = fieldAry[1].trim();
                if ("date".equalsIgnoreCase(filter) && fieldAry.length>2){
                    dateFilter = fieldAry[2].trim();
                }
            }

            field = fieldAry[0].trim();

        }
        IInstanceDataItem data = this.getActionContext().getInstanceData().getItem(field);
        if (data == null && field.indexOf(".") > -1){
            // 处理field逻辑
            param = field.substring(field.indexOf(".") + 1);
            field = field.substring(0, field.indexOf("."));
            data = this.getActionContext().getInstanceData().getItem(field);
        }
        //update by zhangj
        if (data == null || (data.getValue() == null && data.getLogicType() != DataLogicType.Comment)){
        	return "";
        }
        String result = "";

        switch (data.getLogicType()){
            case String:
            case ShortString:
            case Decimal:
            case Double:
            case Int:
            case Html:
            case Long:
            case TimeSpan:
                result = data.getValue() + "";
                break;
            case DateTime:
    			return (data.getValue() == null) ? "" : DateTimeUtil.format((Date) data.getValue(),dateFilter);
            case SingleParticipant:
                result = this.getEngine().getOrganization().GetName(data.getValue() + "");
                break;
            case MultiParticipant:
                {
                    String[] users = (String[]) data.getValue();
                    if (users != null && users.length > 0){
                    	List<String> temp = Arrays.asList(users);
                    	List<Unit> temp2 = this.getEngine().getOrganization().GetUnits(temp);
                    	//Update by linjh
                    	//增加对temp2的判断
                        Unit[] units = null;
                        if(temp2 != null && temp2.size() > 0){
                        	units = temp2.toArray(new Unit[temp2.size()]);
                        }
                        if (units != null){
                            for(Unit unit : units){
                                result += "".equals(result) ? "" : "、";
                                result += unit.getName();
                            }
                        }
                    }
                }
                break;
            case Attachment:
                {
                	List<AttachmentHeader> temp = this.getEngine().getBizObjectManager().QueryAttachment(
                            this.getActionContext().getSchemaCode(),
                            this.getActionContext().getBizObjectID(),
                            field,
                            BoolMatchValue.True,
                            null);
                	//Update by linjh
                	//增加对temp的判断
                	AttachmentHeader[] headers = null;
                	if(temp != null && temp.size() > 0){
                		headers = temp.toArray(new AttachmentHeader[temp.size()]);
                	}
                    if (headers != null){
                        for (int i = 0; i < headers.length; i++){
                            result += "".equals(result) ? "" : "<br>";
                            result += (i + 1) + "、" + headers[i].getFileName();
                        }
                    }
                }
                break;
            case Comment:
                String activity = "";
                String userId = "";
                if (param.toLowerCase().startsWith("activity:")){
                    activity = param.substring(param.indexOf(":") + 1);
                } else if (param.toLowerCase().startsWith("user:")){
                    Unit u = this.getEngine().getOrganization().GetUserByCode(param.substring(param.indexOf(":") + 1));
                    if (u != null){
                    	userId = u.getObjectID();
                    }
                }
                Comment[] comments = GetComments(field, userId, activity);
                if (comments != null){
                    if ("username".equals(param.toLowerCase())){
                        Unit u = this.getEngine().getOrganization().GetUnit(comments[comments.length - 1].getUserID());
                        result = u != null ? u.getName() : comments[comments.length - 1].getUserID();
                    } else if ("datetime".equals(param.toLowerCase())) {
                    	SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");
                        result = sdf2.format(comments[comments.length - 1].getCreatedTime());
                    } else {
                        result = comments[comments.length - 1].getText();
                    }
                }
                break;
            case Bool:
                boolean b = false;
                b = Boolean.parseBoolean(data.getValue() + "");
                result = b ? "true" : "false";
                break;
            case BizObject:
                if (data != null){
                    result = GetBizObjectFieldValue(((BizObject)data), param);
                }
                break;
            case BizObjectArray:
                // 子表打印，需要定义重复节
            	//Update by linjh
            	if (data != null){
                    result = GetBizObjectArrayFieldValue(data, param);
                }
                break;
            default:
                result = "";
                break;
        }
        return result;
    }

    /**
     * @Title: GetBizObjectArrayFieldValue
     * @Description: GetBizObjectArrayFieldValue
     * @Param: @param data
     * @Param: @param param
     * @Param: @return
     * @Return: String
     * @throws
     *  by linjh
     */
	@SuppressWarnings("unused")
	private String GetBizObjectArrayFieldValue(IInstanceDataItem data, String param) {
    	try {
			PropertySchema[] t = ((BizObject[])data.getValue())[0].getSchema().getProperties();
			if(t != null && t.length > 0){
				for(int i=0; i<t.length; i++){
					PropertySchema p = t[i];
					if(!"ObjectID".equals(p.getName())){
						if(p == null){
							return "";
						}
						String result = "";
						switch (p.getLogicType()){
			            	case String:
			            	case ShortString:
			            	case Decimal:
			            	case Double:
			            	case Int:
			            	case Html:
			            	case Long:
			            	case TimeSpan:
			            		result = ((BizObject[])data.getValue())[0].getItem(param) == null? "":((BizObject[])data.getValue())[0].getItem(param).toString();
			            		break;
			            	case DateTime:
			            	case SingleParticipant:
			            		break;
			            	case MultiParticipant:
			            		break;
			            	case Attachment:
				                break;
			            	case Bool:
			            		result = ((BizObject[])data.getValue())[0].getItem(param) == null? "false" :((BizObject[])data.getValue())[0].getItem(param).toString();
			            		break;
			            	default:
			            		result = "";
			            		break;
						}
						return result;
					}
				}
			}
		} catch (Exception e) {
			LOGGER.error("", e);
		}
    	return null;
    }
    
	//update by linwp@Future 2018.8.28 fix HashMap concurrency issue
    private Map<String, Comment[]> DicComments = new ConcurrentHashMap<String, Comment[]>();

    /**
     * @Title: GetComments
     * @Description: 获取审核意见
     * @Param: @param field
     * @Param: @param userId
     * @Param: @param activity
     * @Param: @return
     * @Return: Comment[]
     * @throws Exception
     */
    private Comment[] GetComments(String field, String userId, String activity) throws Exception{
    	String key = field + "." + userId + "." + activity;
        if (DicComments.containsKey(key)){
        	return DicComments.get(key);
        }
        List<Comment> temp = this.getEngine().getBizObjectManager().GetCommentsByInstance(
                this.getActionContext().getSchemaCode(),
                this.getActionContext().getBizObjectID(),
                this.getActionContext().getInstanceId(),
                this.getActionContext().getWorkItemID(),
                field,
                userId,
                activity);
        //Update by linjh
        //打印模板时，增加对temp为null的逻辑处理
        Comment[] comments = null;
        if(temp != null && temp.size() > 0){
        	comments = temp.toArray(new Comment[temp.size()]);
        	DicComments.put(key, comments);
        } else {
        	DicComments.put(key, comments);
        }
        
        return comments;
    }
}
